#ifndef __BE_NAMEEDOBJECTSET__
#define __BE_NAMEEDOBJECTSET__

template<class _Ptr>
class NamedObjectSet
{
private:
  typedef std::tr1::unordered_map< std::string, Handle > StringHandleMap;
  typedef std::tr1::unordered_map< int, _Ptr > HandlePtrMap;
  
  typedef typename StringHandleMap::iterator StringHandleMapIterator;
  typedef typename HandlePtrMap::iterator HandlePtrMapIterator;
  
  typedef typename StringHandleMap::const_iterator StringHandleMapConstIterator;
  typedef typename HandlePtrMap::const_iterator HandlePtrMapConstIterator;
  
  StringHandleMap  name2Handle;
  HandlePtrMap handle2Data;
  
public:
  typedef typename HandlePtrMap::value_type ValueType;

  NamedObjectSet()
  {}
  
  ~NamedObjectSet()
  {}
  
  bool isExist( const std::string & _name ) const
  {
    return !(name2Handle.find( _name ) == name2Handle.end());
  }
  
  bool insert( _Ptr _data )
  {
    if ( isExist( *(_data->getName()) ) )
      {
	return false;
      }
    
    Handle newHandle = Handle::getNewHandle();
    
    _data->setHandle(newHandle);
    
    name2Handle.insert( std::make_pair( *(_data->getName()), newHandle) );
    handle2Data.insert( std::make_pair( newHandle.getId(), _data ) );
    
    return true;
  }

  Handle getHandle( const std::string & _name ) const
  {
    Handle ret;
    StringHandleMapConstIterator it;
    
    it = name2Handle.find( _name );
    
    if ( it == name2Handle.end() )
      return ret;
    
    return it->second;
  }

  _Ptr get( const std::string & _name )
  {
    if ( isExist( _name ) )
      {
	return get( getHandle( _name ) );
      }
    else
      {
	_Ptr obj( new typename _Ptr::element_type() );

	obj->setName( _name );
	insert( obj );

	return obj;
      }
  }

  _Ptr get( const Handle & _handle ) const
  {
    HandlePtrMapConstIterator it;

    it = handle2Data.find( _handle.getId() );
    
    if ( it == handle2Data.end() )
      {
	return _Ptr();
      }

    return it->second;
  }

  template<class _F>
  void foreach(_F &_func)
  {
    std::for_each( handle2Data.begin(), handle2Data.end(), _func);
  }
};

#endif

